<?php

namespace App\Admin\Controllers;

use App\Admin\Traits\RestfulResponse;
use App\Admin\Models\SystemModel;
use App\Admin\Models\SystemMedia;
use App\Admin\Models\Config;
use App\Admin\Models\VueRouter;
use App\Admin\Models\VueAdminUserRouter;
use App\Admin\Requests\ConfigOptionRequest;
use App\Admin\Utils\Admin;
use App\Home\Controllers\Controller as HomeController;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Http\Request;
use Illuminate\Http\UploadedFile;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\DB;

class Controller extends BaseController
{
    use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
    use RestfulResponse;

    /**
     * 保存请求中的文件到 storage，并返回各文件相关的信息
     *
     * @param Request $request
     * @param string $folder 存储的文件夹
     *
     * @return array
     *
     * 返回数据示例
     * [
     *     'file' => [
     *         'origin_filename' => 'origin_filename.jpg',
     *         'filename' => 'filename.jpg',
     *         'ext' => 'jpg',
     *         'path' => '/path/to/filename.jpg',
     *         'size' => 10240,
     *         'mime_type' => 'image/jpeg',
     *     ],
     *     'other' => [...],
     * ]
     */
    protected function saveFiles(Request $request, string $folder = null): array
    {
        $files = $request->file();
        $filesystem_disk = Config::getConfigValue('filesystem_disk','uploads');
        $driver = Storage::disk($filesystem_disk);
        $folder = SystemMedia::UPLOAD_FOLDER_PREFIX.($folder ? '/'.trim($folder, '/') : '');
        $files = array_map(function (UploadedFile $file) use ($driver, $folder) {
            $origin_filename = $file->getClientOriginalName();
            if ($existedFile = SystemMedia::where('origin_filename', $origin_filename)->first()) {
                $existedFile = $existedFile->toArray();
                $existedFile['existed'] = true;
                return $existedFile;
            }
            $md5 = md5_file($file);
            $ext = $file->getClientOriginalExtension();
            $filename = $md5.($ext ? ".{$ext}" : '');
            $path = $driver->putFileAs($folder, $file, $filename);
            if ($path) {
                $url = $driver->url($path);
                return [
                    'origin_filename' => $origin_filename,
                    'filename' => $filename,
                    'ext' => $ext,
                    'path' => env('QINIU_DOMAIN_HTTPS') ? str_replace('http://', 'https://', $url) : $driver->url($path),
                    'size' => $file->getSize(),
                    'mime_type' => $file->getMimeType(),
                    'existed' => false,
                ];
            }
            return ['origin_filename' => $origin_filename];
        }, $files);
        
        return $files;
    }

    /**
     * 根据路径ID获取模型ID
     * @return array $array
     */
    protected function getModelByVid(Int $id){
        // 判断是否强制绑定了model_id，没有则根据模型标识匹配
        if ($modelId = $this->getModelIdByRouteId($id)) {
            return SystemModel::withTrashed()->where('id', $modelId)->first();
        } else {
            // 路径名称
            $formPath = $this->getPathByRouteId($id);
            $path = explode('/', $formPath);
            // 模型标识
            $slug = barToUnderline(current($path));
            // 如果是系统模型表，直接返回
            if ($slug == 'system_models') {
                return [
                    'slug'=>$slug,
                ];
            }
            return SystemModel::withTrashed()
                ->where('parent_id', 0)
                ->where('slug', $slug)
                ->first();
        }
    }

    /**
     * 返回表单页字段
     * @return array $array
     */
    public function formField(
        SystemModel $systemModel,
        Int $id
    ){
        $model = $this->getModelByVid($id);
        if (!$model) {
            return $this->error('没有查询到模型配置，请先更新！');
        }
        // 模型字段
        $list = $systemModel->where('parent_id', $model['id'])
        ->where('form_hide', false)
        ->orderBy('order')
        ->get()
        ->toArray();
        foreach ($list as $key => $value) {
            switch ($value['type']) {
                case SystemModel::TYPE_SINGLE:
                case SystemModel::TYPE_MULTIPLE:
                case SystemModel::TYPE_SELECT_TREE:
                case SystemModel::TYPE_CASCADER:
                    if (isset($value['options']) && $value['options']) {
                        $list[$key]['options'] = parseOptions($value, 'form');
                    }
                    break;
            }
            if ($value['alias']) {
                $list[$key]['group_name'] = $value['name'];
                $list[$key]['name'] = $value['alias'];
            }
        }
      
        // 分组处理
        $list = array_column($list, NULL, 'group_name');
        $result = [];
        foreach ($list as $key => $value) {
            if (strstr($key, '-')) {
                $keyArr = explode('-', $key);
                $result[current($keyArr)]['group'] = current($keyArr);
                $result[current($keyArr)]['slug'] = md5(current($keyArr));
                $value['name'] = str_replace(current($keyArr).'-', '', $value['name']);
                $result[current($keyArr)]['list'][] = $value;
            } else {
                $result[0]['group'] = '-';
                $result[0]['slug'] = null;
                $result[0]['list'][] = $value;
            }
        }
        $result = array_values($result);
        return $this->ok($result);
    }

    /**
     * 返回列表页字段
     * @return array $array
     */
    public function listField(
        SystemModel $systemModel,
        Int $id
    ){
        $field = [
            'slug as field',
            DB::raw('IFNULL(alias, name) AS label'),
            DB::raw('IF(is_virtual>0, "input", type) AS type'),
            'options',
            'list_width',
            'list_fixed',
            'is_virtual'
        ];
        $model = $this->getModelByVid($id);
        if (!$model) {
            return $this->error('没有查询到模型配置，请先更新！');
        }
        // 模型字段
        $list = $systemModel->where('parent_id', $model['id'])
            ->where('list_hide', false);

        // 判断是否有固定列，以决定 orderBy 的方式
        $hasLeftFixed = $hasRightFixed = clone $list;
        $hasLeftFixed = $hasLeftFixed->where('list_fixed', 'left')->exists();
        $hasRightFixed = $hasRightFixed->where('list_fixed', 'right')->exists();
       
        // 如果有左固定列，将其排在最前面
        if ($hasLeftFixed) {
            $list->orderByRaw("CASE WHEN list_fixed = 'left' THEN 0 ELSE 1 END, `order`");
        }

        // 如果有右固定列，将其排在最后面
        if ($hasRightFixed) {
            $list->orderByRaw("CASE WHEN list_fixed = 'right' THEN 1 ELSE 0 END, `order`");
        }
      
        $list = $list->get($field)->toArray();
        foreach ($list as $key => $value) {
            switch ($value['type']) {
                case SystemModel::TYPE_SINGLE:
                case SystemModel::TYPE_MULTIPLE:
                case SystemModel::TYPE_SELECT_TREE:
                case SystemModel::TYPE_CASCADER:
                    if (isset($value['options']) && $value['options']) {
                        $list[$key]['options'] = parseOptions($value, 'list');
                        
                    }
                    break;
            }
        }
        return $this->ok($list);
    }

    /**
     * 返回搜索栏字段
     * @return array $array
     */
    public function searchField(
        SystemModel $systemModel,
        Int $id
    ){
        $field = [
            'slug as field',
            DB::raw('IFNULL(IFNULL(alias, name), slug) AS label'),
            'type',
            'options',
            'filter_rules'
        ];
        $model = $this->getModelByVid($id);
        if (!$model) {
            return $this->error('没有查询到模型配置，请先更新！');
        }
        // 模型字段
        $list = $systemModel->where('parent_id', $model['id'])
            ->where('search_hide', false)
            ->orderBy('order')
            ->get($field)
            ->toArray();
        foreach ($list as $key => $value) {
            switch ($value['type']) {
                case SystemModel::TYPE_SINGLE:
                case SystemModel::TYPE_MULTIPLE:
                case SystemModel::TYPE_SELECT_TREE:
                case SystemModel::TYPE_CASCADER:
                    if (isset($value['options']) && $value['options']) {
                        $list[$key]['options'] = parseOptions($value, 'search');
                    }
                    break;
            }
        }
        return $this->ok($list);
    }

    /**
     * 返回详情页字段
     * @return array $array
     */
    public function detailField(
        SystemModel $systemModel,
        Int $id
    ){
        $field = [
            DB::raw('IFNULL(IFNULL(alias, name), slug) AS name'),
            'slug',
            'type',
            'options',
            'is_virtual'
        ];
        $model = $this->getModelByVid($id);
        if (!$model) {
            return $this->error('没有查询到模型配置，请先更新！');
        }
        // 模型字段
        $list = $systemModel->where('parent_id', $model['id'])
            ->where('detail_hide', false)
            ->orderBy('order')
            ->get($field)
            ->toArray();
        foreach ($list as $key => $value) {
            switch ($value['type']) {
                case SystemModel::TYPE_SINGLE:
                case SystemModel::TYPE_MULTIPLE:
                case SystemModel::TYPE_SELECT_TREE:
                case SystemModel::TYPE_CASCADER:
                    if (isset($value['options']) && $value['options']) {
                        $list[$key]['options'] = parseOptions($value, 'detail');
                    }
                    break;
            }
        }
        return $this->ok($list);
    }

    /**
     * 返回所有关联字段
     * @return array $array
     */
    public function linkField(
        SystemModel $systemModel,
        Int $id
    ){
        // 模型字段
        $list = $systemModel->where('parent_id', $id)
            ->where('form_hide', false)
            ->orderBy('order')
            ->get(['id','created_at','updated_at','slug','name'])
            ->toArray();
        return $this->ok($list);
    }

    /**
     * 返回提示字段
     * @return array $array
     */
    public function hintField(){
        $tables = [];
        $tableNames = DB::getDoctrineSchemaManager()->listTableNames();
        foreach ($tableNames as $tableName) {
            $tableDetails = DB::getDoctrineSchemaManager()->listTableDetails($tableName);
            $columns = $tableDetails->getColumns();
            $tables[$tableName] = [];
            foreach ($columns as $column) {
                $column->getName();
                $tables[$column->getName()] = [];
                $tables[$tableName.'.'.$column->getName()] = [];
            }
        }
        return $this->ok($tables);
    }

    /**
     * 根据模型标识别获取模型ID
     * @return array $array
     */
    protected function getMidBySlug(String $slug){
        // 模型ID
        return SystemModel::where('slug', $slug)->value('id');
    }

    /**
     * 获取当前登录用户的角色ID
     * @return array $array
     */
    public function getRoleId(){
        $user = Admin::user();
        if ($user) {
            return DB::table('admin_user_role')
                ->where('user_id', $user['id'])
                ->pluck('role_id')
                ->toArray();
        } else {
            return [];
        }
    }

    /**
     * 根据模型ID别获取模型标识
     * @return array $array
     */
    protected function getMslugById(Int $id){
        // 模型ID
        return SystemModel::where('id', $id)->value('slug');
    }

    public function getParseOptions(ConfigOptionRequest $configOptionRequest){
        $inputs = $configOptionRequest->validated();
        if (isset($inputs['options'])) {
            $inputs['options'] = parseOptions($inputs, $inputs['scene']);
        }
        return $inputs;
    }

    /**
     * 根据路由ID获取路径
     */
    protected function getPathByRouteId(Int $id)
    {
        if (Admin::isAdministrator()) {
            $path = VueRouter::where('id', $id)->value('path');
        } else {
            $path = VueAdminUserRouter::where('id', $id)->value('path');
        }
        return $path;
    }

    /**
     * 根据路由ID获取模型ID
     */
    protected function getModelIdByRouteId(Int $id)
    {
        if (Admin::isAdministrator()) {
            $modelId = VueRouter::where('id', $id)->value('model_id');
        } else {
            $modelId = VueAdminUserRouter::where('id', $id)->value('model_id');
        }
        return $modelId;
    }

    /**
     * 判断是否是管理员
     */
    protected static function isAdministrator(){
        return Admin::isAdministrator();
    }

    public function __call($name, $arguments)
    {
        call_user_func_array([app(HomeController::class), $name], $arguments);
    }
}